import {NodeA,ASTree} from './tsAST';
import {CFG,statement,conditionStatement,switchStatement} from './cfg';
import {CDG,CDGGEN} from './cdg';
import * as fs from 'fs';
import { DDG, DDGGEN } from './ddg';

export class Edge{
    u:number;//起始节点下标
    v:number;//终止节点下标
    uLine:number;//起始节点行号
    vLine:number;//终止节点行号
    type:number;//边类型,0为cfg,1为cdg,2为ddg
    nxt:number;
    ident:String;
    constructor(u:number,v:number,uLine:number,vLine:number,type:number,nxt:number,ident:String){
        this.u = u;
        this.v = v;
        this.uLine = uLine;
        this.vLine = vLine;
        this.type = type;
        if(nxt==undefined)this.nxt = 0;
        else this.nxt = nxt;
        this.ident=ident;
    }
}
export class CPG{
    cfg:CFG|null;
    cdg:CDG|null;
    ddg:DDG|null;
    cdgGenerator:CDGGEN;
    ddgGenerator:DDGGEN;
    // 节点列表
    stmArray:statement[];//节点列表
    // ast:ASTree;

    // 图属性
    ed:Edge[];//边列表
    first:number[];
    num_e:number;

    addEdge(u:number,v:number,type:number,ident:String){
        let lLine=0,rLine=0;
        if(this.stmArray[u]!=null)lLine = this.stmArray[u].line;
        if(this.stmArray[v]!=null)rLine = this.stmArray[v].line;
        let e:Edge = new Edge(u, v, lLine, rLine, type, this.first[u],ident);
        this.num_e = this.num_e+1;
        this.first[u] = this.num_e;
        this.ed.push(e);
    }
    constructor(cfg:CFG){
        this.stmArray = [];
        this.ed = [];
        this.first = [];
        this.num_e = 0;

        // let fileContent = fs.readFileSync(path, 'utf8');
        // let ast:ASTree=new ASTree(fileContent);
        // this.ast=ast;
        // this.cfg=new CFG(ast.root,"main");
        this.cfg=cfg;
        this.cfg.entry.walked = true;
        this.cfg.resetWalked(this.cfg.entry);
        this.cfg2Array(this.cfg.entry);
        this.cfg.resetWalked(this.cfg.entry);

        let temp = 0;
        if(this.cfg.exit!=null)temp = this.cfg.exit.index;
        this.cdgGenerator = new CDGGEN(this.stmArray.length,0,temp);
        this.ddgGenerator = new DDGGEN(this.stmArray.length,temp,this.stmArray, this.cfg.scopes);
        this.cfgAddEdge(this.cfg.entry);
        this.cfg.resetWalked(this.cfg.entry);
        this.cdgGenerator.init();
        this.ddgGenerator.init();
        this.cdg = this.cdgGenerator.getCDG();
        this.ddg = this.ddgGenerator.getDDG();
        // console.log("fdtst-------------------");
        // console.log(this.graph.fdt);
        // console.log("fdted-------------------");
        for(let i=0;i<=this.cdg.N+9;i++){
            for(var j of this.cdg.v[i]){
                this.addEdge(i, j, 1,"");
            }
        }
        for(let i=0;i<=this.ddg.N+9;i++){
            let siz = this.ddg.v[i].length;
            for(let j=0;j<siz;j++){
                this.addEdge(i,this.ddg.v[i][j], 2,this.ddg.ident[i][j]);
            }
        }
    }

    cfg2Array(stm:statement){
        // console.log(stm);
        // console.log(stm.walked);
        if(stm.walked)
            return;
        stm.walked=true;
        stm.index=this.stmArray.length;
        this.stmArray.push(stm);
        if(stm.type=="ifStatement"||stm.type=="loopStatement"||stm.type=="catchOrNot"){
            let cstm=stm as conditionStatement;
            if(cstm.nextT==null||cstm.nextF==null){
                console.log("ifnext error");
                process.exit();
            }
            this.cfg2Array(cstm.nextF);
            this.cfg2Array(cstm.nextT);
        }
        else if(stm.type=="switchStatement"){
            let sstm=stm as switchStatement;
            for(let ss of sstm.nexts){
                this.cfg2Array(ss);
            }
        }
        else{
            if(stm.next!=null)
                this.cfg2Array(stm.next);
        }
    }
    cfgAddEdge(stm:statement){
        if(stm.walked)
            return;
        stm.walked=true;
        if(stm.type=="ifStatement"||stm.type=="loopStatement"||stm.type=="catchOrNot"){
            let cstm=stm as conditionStatement;
            if(cstm.nextT==null||cstm.nextF==null){
                console.log("ifnext error");
                process.exit();
            }
            this.cdgGenerator.addEdge(cstm.index,cstm.nextF.index)
            this.cdgGenerator.addEdge(cstm.index,cstm.nextT.index)
            this.ddgGenerator.addEdge(cstm.index,cstm.nextF.index)
            this.ddgGenerator.addEdge(cstm.index,cstm.nextT.index)
            this.addEdge(cstm.index,cstm.nextF.index,0,"");
            this.addEdge(cstm.index,cstm.nextT.index,0,"")
            this.cfgAddEdge(cstm.nextF);
            this.cfgAddEdge(cstm.nextT);
        }
        else if(stm.type=="switchStatement"){
            let sstm=stm as switchStatement;
            for(let ss of sstm.nexts){
                this.cdgGenerator.addEdge(sstm.index,ss.index)
                this.ddgGenerator.addEdge(sstm.index,ss.index)
                this.addEdge(sstm.index,ss.index,0,"")
                this.cfgAddEdge(ss);
            }
        }
        else{
            if(stm.next!=null){
                this.cdgGenerator.addEdge(stm.index,stm.next.index)
                this.ddgGenerator.addEdge(stm.index,stm.next.index)
                this.addEdge(stm.index,stm.next.index,0,"")
                this.cfgAddEdge(stm.next);
            }
        }
    }

}